#!/usr/bin/env node
const path = require('path');
const { Readable } = require('stream');
const Koa = require('koa');
const send = require('koa-send');
const compilerSFC = require('@vue/compiler-sfc');

const app = new Koa();

const stream2String = (stream) =>
  new Promise((resolve, reject) => {
    const chunks = [];
    stream.on('data', (chunk) => chunks.push(chunk));
    stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
    stream.on('error', reject);
  });

const string2Stream = (text) => {
  const stream = new Readable();
  stream.push(text);
  stream.push(null); // 标记完成

  return stream;
};

// 3. 加载第三方模块
app.use(async (ctx, next) => {
  // ctx.path --> /@modules/vue
  if (ctx.path.startsWith('/@modules/')) {
    const moduleName = ctx.path.substr(10);
    const pkgPath = path.join(
      process.cwd(),
      'node_modules',
      moduleName,
      'package.json'
    );
    const pkg = require(pkgPath);
    ctx.path = path.join('/node_modules', moduleName, pkg.module);
  }

  await next();
});

// 1. 静态文件服务器
app.use(async (ctx, next) => {
  await send(ctx, ctx.path, { root: process.cwd(), index: 'index.html' });
  await next();
});

// 4. 处理单文件组件
app.use(async (ctx, next) => {
  if (ctx.path.endsWith('.vue')) {
    const contents = await stream2String(ctx.body);
    // console.log('ctx.path :', ctx.path, 'contents :', contents);
    const { descriptor } = compilerSFC.parse(contents);
    console.log('descriptor :', descriptor);
    let code;

    // vite@1.x
    if (!ctx.query.type) {
      code = descriptor.script.content;
      console.log(code);
      code = code.replace(/export\s+default\s+/g, 'const __script = ');
      code += `
import {render as __render} from "${ctx.path}?type=template"
__script.render = __render
export default __script
`;
    } else if (ctx.query.type === 'template') {
      const templateRender = compilerSFC.compileTemplate({
        source: descriptor.template.content,
      });
      code = templateRender.code;
    }
    ctx.type = 'application/javascript';
    ctx.body = string2Stream(code);
  }

  await next();
});

// 2. 修改第三方模块路径
app.use(async (ctx, next) => {
  if (ctx.type === 'application/javascript') {
    const contents = await stream2String(ctx.body);
    // import Vue from 'vue'
    // import App from './App.vue'
    ctx.body = contents
      .replace(/(from\s+['"])(?![\.\/])/g, '$1/@modules/')
      .replace(/process\.env\.NODE_ENV/g, '"development"');
  }
});

app.listen(3001);
console.log('Server running @ http://localhost:3001');
